package com.huwaiwai.lock;

import com.huwaiwai.lock.mylock.MyLock;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by hww on 2019/1/8 3:26 PM.
 */
public class Test {

    public static void main(String [] args) throws InterruptedException {
        testPhaser();
    }

    /**
     * phaser 可以通过register方法注册  动态变更CyclicBarrier的初始数量
     */
    private static void testPhaser() {

        ExecutorService executorService = Executors.newCachedThreadPool();
        Phaser phaser = new Phaser();
        // 1. 注册一个 party
        phaser.register();

        for (int i = 0; i < 5; i++) {
            phaser.register();
            executorService.submit(() -> {
                // 2. 每个线程到这里进行阻塞，等待所有线程到达栅栏
                phaser.arriveAndAwaitAdvance();

                // doWork()
                System.out.println(Thread.currentThread().getName() + "   do...");
            });
        }
        phaser.arriveAndAwaitAdvance();
    }

    /**
     * for循环是为了多次测试 展示想要的现象
     *
     * for循环里面的内容大致意思如下
     * 1.创建两个线程t1,t2  执行的内容是拿到m的对象锁以后，执行wait方法等待
     * 2.启动t1,t2线程后，在主线程中按顺序执行t1中断，唤醒m对象的等待线程
     * 3.理论上来说  t1会由于中断而退出  t2正常响应wait方法
     * 4.测试结果 上述3的猜想不正确  某些情况下t1正常返回，而t2一直等待
     * @throws InterruptedException
     */
    private static void testInterruptedAndNotify() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Object m = new Object();
            Thread t1 = new Thread(() -> {
                String name = Thread.currentThread().getName();
                // 挂起
                synchronized (m) {
                    try {
                        m.wait();
                    } catch (InterruptedException e) {
                        System.out.println(name + " after wait InterruptedException time=" + new Date());
                    }
                }
                // 解除挂起
                System.out.println(name + " after wait time=" + new Date());
            });
            Thread t2 = new Thread(() -> {
                String name = Thread.currentThread().getName();
                // 挂起
                synchronized (m) {
                    try {
                        m.wait();
                    } catch (InterruptedException e) {
                        System.out.println(name + " after wait InterruptedException time=" + new Date());
                    }
                }
                // 解除挂起
                System.out.println(name + " after wait time=" + new Date());
            });
            t1.start();
            t2.start();
            Thread.sleep(1000L);

            synchronized (m) {
                t1.interrupt();
                m.notify();
            }
            Thread.sleep(1000L);
            System.out.println();
        }
    }


    /**
     * 如果中断被挂起的线程 线程会唤醒
     * @throws InterruptedException
     */
    private static void testInterruptAfterPark() throws InterruptedException {
        Thread t = new Thread(() -> {
            System.out.println("start time=" + new Date());
            // 挂起
            LockSupport.park();
            // 解除挂起
            System.out.println("unpark  time=" + new Date());
        });

        // 子线程启动即挂起
        t.start();

        Thread.sleep(5000L);
        // 5秒后主线程中断 挂起的子线程
        t.interrupt();

        Thread.sleep(5000L);
        // 10秒后主线程  唤醒挂起的子线程
        LockSupport.unpark(t);

    }

    /**
     * 在挂起(park)线程前  先调用恢复方法(unpark) 则会在调用park之后马上就恢复线程
     * @throws InterruptedException
     */
    private static void testPrePark() throws InterruptedException {
        Thread t = new Thread(() -> {
            System.out.println("start time=" + new Date());
            try {
                // 让线程先睡10秒
                Thread.sleep(10000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("park time=" + new Date());
            // 挂起
            LockSupport.park();
            // 解除挂起
            System.out.println("unpark  time=" + new Date());
        });
        // 子线程 启动后10秒才会被挂起
        t.start();
        // 主线程延迟5秒后 唤起子线程  此时其实还没被挂起
        Thread.sleep(5000L);

        LockSupport.unpark(t);

    }

    /**
     * 线程被挂起(park)后，需要通过恢复(unpark)方法唤醒线程
     * @throws InterruptedException
     */
    private static void testPark() throws InterruptedException {
        Thread t = new Thread(() -> {
            System.out.println("park time=" + new Date());
            // 挂起
            LockSupport.park();
            // 解除挂起
            System.out.println("unpark  time=" + new Date());
        });
        // 子线程 启动后就被挂起
        t.start();
        // 主线程延迟5秒后 唤起子线程
        Thread.sleep(5000L);
        LockSupport.unpark(t);
    }

    private static void test02() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        lock.lock();
        new Thread(lock::lock).start();

    }

    private static void test01() {
        MyLock lock = new MyLock();
        System.out.println(lock.holdCount());
        lock.lock();
        System.out.println(lock.holdCount());
        lock.lock();
        System.out.println(lock.holdCount());
        lock.unlock();
        System.out.println(lock.holdCount());
        lock.unlock();
        System.out.println(lock.holdCount());
        lock.unlock();
        System.out.println(lock.holdCount());

    }


}
